///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2012 - PG-soft
///
/// Original filename: EagleEyes.c
/// Project          : EagleEyes
/// Date of creation : 2012-01-17
/// Author(s)        : ProgrammeBoy
///
/// Purpose          : <description>
///
/// Revisions:
///  0000 [2012-01-17] Initial revision.
///
///////////////////////////////////////////////////////////////////////////////

#include <ntifs.h>

#include "eagleeyes.h"
#include "process.h"
#include "ssdt.h"
#include "memory.h"
#include "idt.h"
#include "sysmodule.h"
#include "fsd.h"
#include "callback.h"

#include "disasm.h"

PDRIVER_OBJECT gEEyesDriverObject = 0;

NTSTATUS 
EAGLEEYES_DispatchCreateClose(
    IN PDEVICE_OBJECT		DeviceObject,
    IN PIRP					Irp
)
{
    NTSTATUS status = STATUS_SUCCESS;
    Irp->IoStatus.Status = status;
    Irp->IoStatus.Information = 0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;
}

NTSTATUS 
EAGLEEYES_DispatchDeviceControl(
    IN PDEVICE_OBJECT		DeviceObject,
    IN PIRP					Irp
)
{
    NTSTATUS status = STATUS_SUCCESS;
    ULONG RetLength;
    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
    PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
    PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
    ULONG InputLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
    ULONG OutputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
    
    //
    //  Init the out length
    //
    
    RetLength = 0;

    switch(irpSp->Parameters.DeviceIoControl.IoControlCode)
    {
    case IOCTL_EAGLEEYES_MEM_READ:
        {
            if (InputLength != sizeof(READ_INFO)){
                Irp->IoStatus.Information = 0;
                status = STATUS_INVALID_PARAMETER;
                break;
            }
            status = ReadKernelMemory(  OutputBuffer,
                                        ((PREAD_INFO)InputBuffer)->Address,
                                        ((PREAD_INFO)InputBuffer)->Length);
            Irp->IoStatus.Information = OutputLength;
        }
        break;
    case IOCTL_EAGLEEYES_MEM_WRITE:
        {

        }
        break;
    case IOCTL_EAGLEEYES_SSDT_INFO:
        {
            status = QuerySSDTInfo(OutputBuffer, OutputLength, &RetLength);
            Irp->IoStatus.Information = RetLength;
        }
        break;
    case IOCTL_EAGLEEYES_SSDT_ENTRY:
        {
            status = QuerySSDTEntrys(OutputBuffer, OutputLength, &RetLength);
            Irp->IoStatus.Information = RetLength;
        }
        break;
    case IOCTL_EAGLEEYES_SHADOWSSDT_INFO:
        {
            status = QueryShadowSSDTInfo(OutputBuffer, OutputLength, &RetLength);
            Irp->IoStatus.Information = RetLength;
        }
        break;
    case IOCTL_EAGLEEYES_SHADOWSSDT_ENTRY:
        {
            status = QueryShadowSSDTEntrys(OutputBuffer, OutputLength, &RetLength);
            Irp->IoStatus.Information = RetLength;
        }
        break;
	case IOCTL_EAGLEEYES_IDT_COUNTS:
		{
			if (OutputLength != sizeof(ULONG)){
				Irp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER; 
				break;
			}
			*(PULONG)OutputBuffer = QueryIDTEntryCounts();
			Irp->IoStatus.Information = sizeof(ULONG);
		}
		break;
	case IOCTL_EAGLEEYES_IDT_ENTRYS:
		{
			status = QueryIDTEntrys(OutputBuffer, OutputLength, &RetLength);
			Irp->IoStatus.Information = RetLength;
		}
		break;
    case IOCTL_EAGLEEYES_PROCESS_INFO1_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
				Irp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER; 
				break;
			}
            status = QueryProcessInfoListByAPI(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO1:
        {
            status = QueryProcessInfoListByAPI(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO2_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
				Irp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER; 
				break;
			}
            status = QueryProcessInfoListByCidTable(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO2:
        {
            status = QueryProcessInfoListByCidTable(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO3_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
				Irp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER; 
				break;
			}
            status = QueryProcessInfoListByActiveList(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO3:
        {
            status = QueryProcessInfoListByActiveList(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO4_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
				Irp->IoStatus.Information = 0;
				status = STATUS_INVALID_PARAMETER; 
				break;
			}
            status = QueryProcessInfoListByHandleTable(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_PROCESS_INFO4:
        {
            status = QueryProcessInfoListByHandleTable(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;

    case IOCTL_EAGLEEYES_SYSTEM_MOD_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
                Irp->IoStatus.Information = 0;
                status = STATUS_INVALID_PARAMETER; 
                break;
            }
            status = QuerySysModuleListByPsLdModList(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_SYSTEM_MOD_INFO:
        {
            status = QuerySysModuleListByPsLdModList(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    
     case IOCTL_EAGLEEYES_FSD_HOOK_LEN:
        {
            if (OutputLength != sizeof(ULONG)){
                Irp->IoStatus.Information = 0;
                status = STATUS_INVALID_PARAMETER; 
                break;
            }
            status = QueryFsdHookInfo(NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_FSD_HOOK_INFO:
        {
            status = QueryFsdHookInfo(OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;

     case IOCTL_EAGLEEYES_CALLBACK_LEN:
        {
            if (OutputLength != sizeof(ULONG) ||
                InputLength  != sizeof(ULONG)){
                Irp->IoStatus.Information = 0;
                status = STATUS_INVALID_PARAMETER; 
                break;
            }
            status = GetCallbacks((CALLBACK_TYPE)InputBuffer, NULL, NULL, &RetLength);
            if (STATUS_INFO_LENGTH_MISMATCH == status){
                *(PULONG)OutputBuffer = RetLength;
                Irp->IoStatus.Information = sizeof(ULONG);
                status = STATUS_SUCCESS;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;
    case IOCTL_EAGLEEYES_CALLBACK_INFO:
        {
            status = GetCallbacks((CALLBACK_TYPE)InputBuffer, OutputBuffer, OutputLength, &RetLength);
            if (NT_SUCCESS(status)){
                Irp->IoStatus.Information = RetLength;
            }else{
                Irp->IoStatus.Information = 0;
            }
        }
        break;

    default:
        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Information = 0;
        break;
    }
    
    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return status;
}

VOID 
EAGLEEYES_DriverUnload(
    IN PDRIVER_OBJECT		DriverObject
)
{
    PDEVICE_OBJECT pdoNextDeviceObj = gEEyesDriverObject->DeviceObject;
	UNICODE_STRING uniSymblicName;

	RtlInitUnicodeString(&uniSymblicName, SYMLINK_NAME);
    IoDeleteSymbolicLink(&uniSymblicName);

    //
	// Delete all the device objects
    //
	
	while(pdoNextDeviceObj)
    {
        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
        IoDeleteDevice(pdoThisDeviceObj);
    }
}

NTSTATUS 
DriverEntry(
    IN OUT PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING      RegistryPath
)
{
    PDEVICE_OBJECT pdoDeviceObj = 0;
	UNICODE_STRING uniDeviceName;
	UNICODE_STRING uniSymblicName;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    gEEyesDriverObject = DriverObject;

    //
	// Create the device object.
    //
	
	RtlInitUnicodeString(&uniDeviceName, DEVICE_NAME);
	RtlInitUnicodeString(&uniSymblicName, SYMLINK_NAME);

	if(!NT_SUCCESS(status = IoCreateDevice(
                        DriverObject,
                        0,
                        &uniDeviceName,
                        FILE_DEVICE_UNKNOWN,
                        FILE_DEVICE_SECURE_OPEN,
                        FALSE,
                        &pdoDeviceObj
                        ))){
        //
		// Bail out (implicitly forces the driver to unload).
        //
		
		return status;
    }

    //
	// Now create the respective symbolic link object
    //
	
	if(!NT_SUCCESS(status = IoCreateSymbolicLink(
                        &uniSymblicName,
                        &uniDeviceName
                        ))){
        IoDeleteDevice(pdoDeviceObj);
        return status;
    }

    //
	// NOTE: You need not provide your own implementation for any major function that
    //       you do not want to handle. I have seen code using DDKWizard that left the
    //       *empty* dispatch routines intact. This is not necessary at all!
    //
	
	DriverObject->MajorFunction[IRP_MJ_CREATE] =
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = EAGLEEYES_DispatchCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = EAGLEEYES_DispatchDeviceControl;
    DriverObject->DriverUnload = EAGLEEYES_DriverUnload;
    
    DriverObject->Flags |= DO_BUFFERED_IO;

    return STATUS_SUCCESS;
}
